import nltk.corpus, nltk.tag, itertools
from nltk.tag import brill
from nltk.tag import sequential

brown_reviews   = nltk.corpus.brown.tagged_sents(categories=['reviews'])
brown_lore      = nltk.corpus.brown.tagged_sents(categories=['lore'])
brown_fiction   = nltk.corpus.brown.tagged_sents(categories=['fiction'])
brown_scifi     = nltk.corpus.brown.tagged_sents(categories=['science_fiction'])
brown_adventure = nltk.corpus.brown.tagged_sents(categories=['adventure'])
brown_mystery   = nltk.corpus.brown.tagged_sents(categories=['mystery'])

brown_train = list(itertools.chain(brown_reviews[:1000],
                                   brown_lore[:1000],
                                   brown_fiction[:1000],
                                   brown_scifi[:1000],
                                   brown_adventure[:1000],
                                   brown_mystery[:1000]))
brown_test  = list(itertools.chain(brown_reviews[1000:2000],
                                   brown_lore[1000:2000],
                                   brown_fiction[1000:2000],
                                   brown_scifi[1000:2000],
                                   brown_adventure[1000:2000],
                                   brown_mystery[1000:2000]))

train_sents = brown_train
test_sents  = brown_test

def backoff_tagger(tagged_sents, tagger_classes, backoff=None):
    if not backoff:
        backoff = tagger_classes[0](tagged_sents)
        del tagger_classes[0]

    for cls in tagger_classes:
        tagger = cls(tagged_sents, backoff=backoff)
        backoff = tagger

    return backoff

# Unigram - Bigram - Trigram
ubt_tagger = backoff_tagger(train_sents, [nltk.tag.UnigramTagger,
                                          nltk.tag.BigramTagger,
                                          nltk.tag.TrigramTagger])
# Unigram - Trigram - Bigram
utb_tagger = backoff_tagger(train_sents, [nltk.tag.UnigramTagger,
                                          nltk.tag.TrigramTagger,
                                          nltk.tag.BigramTagger])
# Bigram - Unigram - Trigram
but_tagger = backoff_tagger(train_sents, [nltk.tag.BigramTagger,
                                          nltk.tag.UnigramTagger,
                                          nltk.tag.TrigramTagger])
# Bigram - Trigram - Unigram
btu_tagger = backoff_tagger(train_sents, [nltk.tag.BigramTagger,
                                          nltk.tag.TrigramTagger,
                                          nltk.tag.UnigramTagger])
# Trigram - Unigram - Bigram
tub_tagger = backoff_tagger(train_sents, [nltk.tag.TrigramTagger,
                                          nltk.tag.UnigramTagger,
                                          nltk.tag.BigramTagger])
# Trigram - Bigram - Unigram
tbu_tagger = backoff_tagger(train_sents, [nltk.tag.TrigramTagger,
                                          nltk.tag.BigramTagger,
                                          nltk.tag.UnigramTagger])

# Unigram - Bigram - Trigram - Affix
ubta_tagger = backoff_tagger(train_sents, [nltk.tag.UnigramTagger,
                                           nltk.tag.BigramTagger,
                                           nltk.tag.TrigramTagger,
                                           nltk.tag.AffixTagger])
# Unigram - Bigram - Affix - Trigram
ubat_tagger = backoff_tagger(train_sents, [nltk.tag.UnigramTagger,
                                           nltk.tag.BigramTagger,
                                           nltk.tag.AffixTagger,
                                           nltk.tag.TrigramTagger])
# Unigram - Affix - Bigram - Trigram
uabt_tagger = backoff_tagger(train_sents, [nltk.tag.UnigramTagger,
                                           nltk.tag.AffixTagger,
                                           nltk.tag.BigramTagger,
                                           nltk.tag.TrigramTagger])
# Affix - Unigram - Bigram - Trigram
aubt_tagger = backoff_tagger(train_sents, [nltk.tag.AffixTagger,
                                           nltk.tag.UnigramTagger,
                                           nltk.tag.BigramTagger,
                                           nltk.tag.TrigramTagger])

word_patterns = [
	(r'^-?[0-9]+(.[0-9]+)?$', 'CD'),
	(r'.*ould$', 'MD'),
	(r'.*ing$', 'VBG'),
	(r'.*ed$', 'VBD'),
	(r'.*ness$', 'NN'),
	(r'.*ment$', 'NN'),
	(r'.*ful$', 'JJ'),
	(r'.*ious$', 'JJ'),
	(r'.*ble$', 'JJ'),
	(r'.*ic$', 'JJ'),
	(r'.*ive$', 'JJ'),
	(r'.*ic$', 'JJ'),
	(r'.*est$', 'JJ'),
	(r'^a$', 'PREP'),
]

# Affix - Unigram - Bigram - Trigram - Reg-Exp
aubtr_tagger = nltk.tag.RegexpTagger(word_patterns,
                                     backoff=aubt_tagger)
# Reg-Exp - Affix - Unigram - Bigram - Trigram
raubt_tagger = backoff_tagger(train_sents,
                              [nltk.tag.AffixTagger,
                               nltk.tag.UnigramTagger,
                               nltk.tag.BigramTagger,
                               nltk.tag.TrigramTagger],
                              backoff=nltk.tag.RegexpTagger(word_patterns))

# Template for the FastBrillTaggerTrainer
templates = [
    brill.SymmetricProximateTokensTemplate(brill.ProximateTagsRule, (1,1)),
    brill.SymmetricProximateTokensTemplate(brill.ProximateTagsRule, (2,2)),
    brill.SymmetricProximateTokensTemplate(brill.ProximateTagsRule, (1,2)),
    brill.SymmetricProximateTokensTemplate(brill.ProximateTagsRule, (1,3)),
    brill.SymmetricProximateTokensTemplate(brill.ProximateWordsRule, (1,1)),
    brill.SymmetricProximateTokensTemplate(brill.ProximateWordsRule, (2,2)),
    brill.SymmetricProximateTokensTemplate(brill.ProximateWordsRule, (1,2)),
    brill.SymmetricProximateTokensTemplate(brill.ProximateWordsRule, (1,3)),
    brill.ProximateTokensTemplate(brill.ProximateTagsRule, (-1, -1), (1,1)),
    brill.ProximateTokensTemplate(brill.ProximateWordsRule, (-1, -1), (1,1))
]

trainer = brill.FastBrillTaggerTrainer(raubt_tagger, templates)

# Brill - Reg-Exp - Affix - Unigram - Bigram - Trigram
braubt_tagger = trainer.train(train_sents,
                              max_rules=100,
                              min_score=3)

cpos_tagger  = sequential.ClassifierBasedPOSTagger(train=train_sents)
bcpos_tagger = sequential.ClassifierBasedPOSTagger(train=train_sents,
                                                   backoff=raubt_tagger)
pos_tagger = nltk.data.load(nltk.tag._POS_TAGGER)

def test_taggers():
    taggers = [ubt_tagger, aubt_tagger, raubt_tagger, braubt_tagger, cpos_tagger, bcpos_tagger, pos_tagger]
    for t in taggers:
        print(str((nltk.tag.accuracy(t,test_sents))*100)+'%')

def gold_evaluation():
    taggers = [ubt_tagger, aubt_tagger, raubt_tagger, braubt_tagger, cpos_tagger, bcpos_tagger, pos_tagger]
    results = [nltk.tag.api.t.evaluate(gold) for t in taggers]
    del taggers
    for r in results:
        print(str(r*100)+'%')
        
def compare_tagger_output(sent):
    taggers = [ubt_tagger,
               aubt_tagger,
               raubt_tagger,
               braubt_tagger,
               pos_tagger,
               cpos_tagger,
               bcpos_tagger]
    for t in taggers:
        print(str(t.tag(nltk.word_tokenize(sent))))

